﻿using System;
using System.IO;
using NUnit.Framework;
using OpenWaves.Caching;

namespace OpenWaves.UnitTests.Caching
{
    [TestFixture]
    public class FileSystemCacheTests
    {
        private string directory;

        [SetUp]
        public void Setup()
        {
            this.directory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
        }

        [TearDown]
        public void TearnDown()
        {
            if (Directory.Exists(this.directory))
                Directory.Delete(this.directory, true);
        }

        [Test]
        public void GIVEN_empty_cache_WHEN_value_is_added_THEN_it_can_be_retrieved()
        {
            const string expectedValue = "Value1";
            string actualValue;
            using (var cache = CreateCache())
            {
                cache.InsertValue("key", expectedValue, TimeSpan.MaxValue);
                actualValue = cache.GetValue("key");
            }

            Assert.That(actualValue, Is.EqualTo(expectedValue));
        }

        [Test]
        public void GIVEN_value_is_in_cache_WHEN_it_expires_THEN_it_cannot_be_retrieved()
        {
            using (var cache = CreateCache())
            {
                using (var fakeTime = FakeTimeScope.Begin())
                {
                    cache.InsertValue("key", "Value", TimeSpan.FromHours(1));
                    fakeTime.Forward(TimeSpan.FromHours(2));
                    Assert.That(cache.GetValue("key"), Is.Null);
                }
            }
        }

        [Test]
        public void GIVEN_value_is_in_cache_WHEN_it_is_evicted_THEN_it_cannot_be_retrieved()
        {
            using (var cache = CreateCache())
            {
                cache.InsertValue("key", "Value", TimeSpan.MaxValue);
                cache.EvictValue("key");

                Assert.That(cache.GetValue("key"), Is.Null);
            }
        }

        [Test]
        public void GIVEN_non_empty_cache_directory_WHEN_new_cache_instance_is_created_in_the_same_directory_THEN_value_can_be_retrieved()
        {
            const string expectedValue = "Value1";
            using (var cache1 = CreateCache())
            {
                cache1.InsertValue("key", expectedValue, TimeSpan.MaxValue);
            }

            string actualValue;
            using (var cache2 = CreateCache())
            {
                actualValue = cache2.GetValue("key");
            }

            Assert.That(actualValue, Is.EqualTo(expectedValue));

        }

        private FileSystemCache<string> CreateCache()
        {
            var cache = new FileSystemCache<string>(
                this.directory,
                (s, stream) =>
                    {
                        var writer = new StreamWriter(stream);
                        writer.Write(s);
                        writer.Flush();
                    },
                stream => new StreamReader(stream).ReadToEnd());
            return cache;
        }
    }
}